#include <ux86.h>
#include <kbddefs.h>
#include <uprocess.h>
#include "i8042.h"
#include "kbddrv.h"
#include <ustdio.h>
void uprinti(uint32_t i);
uint8_t currently_held_key = 0x00;
uint8_t extended = 0;
int sigfile_hndl = 0;

void notify_dec(){
	if (sigfile_hndl == 0){
		sigfile_hndl = uopen("/dev/kbdsig",1,0);
		if (sigfile_hndl == -1){
			sigfile_hndl = 0;
			return;
		}
	}
	char c = 0xFF;
	uwrite(sigfile_hndl,(uint8_t *)&c,1);
}

uint8_t kbd_controller_status(){
	return _inp(KBD_CTRL_IO_PORT);
}

void kbd_send_controller_command(uint8_t cmd){
	while(1)
		if((kbd_controller_status() & KBD_CTRL_STATUS_IN_BUF_BIT) == 0)
			break;
	_outp(KBD_CTRL_IO_PORT,cmd);
}

uint8_t kbd_encoder_read_buffer(){
	return _inp(KBD_ENC_IO_PORT);
}

void kbd_send_encoder_command(uint8_t cmd){
	while(1)
		if((kbd_controller_status() & KBD_CTRL_STATUS_IN_BUF_BIT) == 0)
			break;
	_outp(KBD_ENC_IO_PORT,cmd);
}

void kbd_isr(registers_t regs){
	uint8_t scancode;
	uprint("Keyboard read [pid=");
	uprinti(ugetpid());
	uprint("]\n");
	if (kbd_controller_status () & KBD_CTRL_STATUS_OUT_BUF_BIT){
		scancode = kbd_encoder_read_buffer();
		if ((scancode == 0xE0) || (scancode == 0xE1)){
			extended = 1;
			return;
		}
		if (scancode & 0x80){
			kb_released(currently_held_key);//
			if ((currently_held_key & 0x80) == scancode)
				return;
			scancode &= ~0x80;
			switch (scancode){
				case 0x1D:
					kb_clear_modifier(KBD_CTRL_BIT);
					break;
				case 0x38:
					kb_clear_modifier(KBD_ALT_BIT);
					break;
				case 0x2A:
				case 0x36:
					if (!extended)
					kb_clear_modifier(KBD_SHIFT_BIT);
					break;
				case 0x5B:
				case 0x5C:
					if (extended)
						kb_clear_modifier(KBD_WIN_BIT);
					break;
				case 0x5D:
					if (extended)
						kb_clear_modifier(KBD_MENU_BIT);
					break;
			}
			return;		
		}
		if (scancode == currently_held_key){
			kb_typed(scancode);//
			return;
		}
		currently_held_key = scancode;
		kb_pressed(scancode);//
		switch (scancode){
				case 0x1D:
					kb_set_modifier(KBD_CTRL_BIT);
					break;
				case 0x38:
					kb_set_modifier(KBD_ALT_BIT);
					break;
				case 0x2A:
				case 0x36:
					if (!extended)
					kb_set_modifier(KBD_SHIFT_BIT);
					break;
				case 0x5B:
				case 0x5C:
					if (extended)
						kb_set_modifier(KBD_WIN_BIT);
					break;
				case 0x5D:
					if (extended)
						kb_set_modifier(KBD_MENU_BIT);
					break;
				case 0x3A:
					if (!extended)
					kb_toggle_modifier(KBD_CPSLCK_BIT);
					break;
				case 0x46:
					if (!extended)
					kb_toggle_modifier(KBD_SCLLCK_BIT);
					break;
				case 0x45:
					if (!extended)
					kb_toggle_modifier(KBD_NUMLCK_BIT);
					break;
			}	
		notify_dec();
	}
}